#include<queue>
#include<pthread.h>

namespace BlockQueueModule
{   
    static const int gcap=10;


    template<class T>
    class BlockQueue
    {
    public:
        BlockQueue(int cap=gcap)
        :_cap(cap)
        ,_cwait_num(0)
        ,_pwait_num(0)
        {
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_productor_cond,nullptr);
            pthread_cond_init(&_consumer_cond,nullptr);
        }

        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_productor_cond);
            pthread_cond_destroy(&_consumer_cond);

        }
        bool isfull()
        {
            return _cap==_q.size();
        }
        
        bool isempty()
        {
            return _q.size()==0;
        }

        void Equeue(const T& in)
        {
            pthread_mutex_lock(&_mutex);
            
            while(isfull())//
            {
                _pwait_num++;
                pthread_cond_wait(&_productor_cond,&_mutex);
                _pwait_num--;
            }

            //不是满 || 一开始满处理好被唤醒一定不满
            _q.push(in);

            if(_cwait_num)
            {
                pthread_cond_signal(&_consumer_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }

        void pop(T* out)
        {
            pthread_mutex_lock(&_mutex);
            while(isempty())
            {
                _cwait_num++;
                pthread_cond_wait(&_consumer_cond,&_mutex);
                _cwait_num--;
            }

            *out=_q.front();
            _q.pop();

            if(_pwait_num)
            {
                pthread_cond_signal(&_productor_cond);
            }
            pthread_mutex_unlock(&_mutex);

        }


    private:
        std::queue<T> _q;//临界资源队列
        int _cap;//最大资源数
        pthread_mutex_t _mutex;//互斥
        pthread_cond_t _productor_cond;//生产者条件变量  维护生产者队列
        pthread_cond_t _consumer_cond;//消费者条件变量  维护消费者队列


        int _cwait_num;
        int _pwait_num;




    };
}